package org.dna.wickwtui;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.panel.Panel;
import org.dna.MetroApplication;
import org.dna.metronomo.persistence.Activity;
import org.dna.uimodel.MenuItem;
import org.dna.uimodel.SelectableActivity;
import org.dna.wickwtui.users.IContextMenuProvider;

public abstract class MetroPage extends WebPage {
	private static final Logger LOG = Logger.getLogger(MetroPage.class);
	
	private SummaryPanel pnlSummary;
	
	protected Panel m_currentPanel;
	protected List<MenuItem> m_pageContextMenu;
	protected Map<Class<? extends Panel>, Panel> m_panelsMap = new HashMap<Class<? extends Panel>, Panel>();
	
	public MetroPage() {
		pnlSummary = new SummaryPanel("summaryPanel");
		add(pnlSummary);
		add(new MenuPanel("menuPanel"));
		add(new UserPanel("userPanel", LoginPage.class));
	}

	public static List<SelectableActivity> allActivities() {
		List<Activity> activities = MetroApplication.get().getActivityDAO().allActivities();
		List<SelectableActivity> res = new ArrayList<SelectableActivity>(activities.size());
		for (Activity act : activities) {
			res.add(new SelectableActivity(act));
		}
		return res;
	}
	
	public void setContextMenu(List<MenuItem> contextmenu) {
		pnlSummary.setContextMenu(contextmenu);
	}
	
	/**
	 * Updates the context menu shared by all page panels with the other menus
	 * offered by the current panel.
	 * */
	protected void updateContextMenu() {
		List<MenuItem> currentMenu = new ArrayList<MenuItem>(m_pageContextMenu);
		if (m_currentPanel instanceof IContextMenuProvider) {
        	List<MenuItem> panelContextMenu = ((IContextMenuProvider) m_currentPanel).prepare();
        	currentMenu.addAll(panelContextMenu);
        }
		setContextMenu(currentMenu);
	}
	
	/**
	 * Switch the current displayed panel to that represented by the class passed
	 * into.
	 * 
	 * @param clazz the target panel's class to switch.
	 * */
	public void switchToPanel(Class<? extends Panel> clazz) {
		Panel inst = m_panelsMap.get(clazz);
		if (inst == null) {
			throw new RuntimeException("Can't find a panel of class" + clazz
					+ " to switch");
		}
		m_currentPanel.replaceWith(inst);
		m_currentPanel = inst;
		updateContextMenu();
	}

	/**
	 * Switch the current displayed panel to that represented by the class passing
	 * the argument to the constructor.
	 * 
	 * @param clazz the target panel's class to switch.
	 * @param arg the constructor's argument for the target class.
	 * */
    public void switchToPanel(Class<? extends Panel> clazz, Object arg) {
        Panel p = null;
        try {
            Constructor<? extends Panel> constr = clazz.getDeclaredConstructor(String.class, arg.getClass());
            p = constr.newInstance("innerPanel", arg);
        } catch (InstantiationException ex) {
            LOG.log(Level.FATAL, "Can't instantiate page " + clazz, ex);
        } catch (IllegalAccessException ex) {
            LOG.log(Level.FATAL, "Can't instantiate page " + clazz, ex);
        } catch (InvocationTargetException ex) {
            LOG.log(Level.FATAL, "Can't instantiate page " + clazz + ", constructor throw an exception", ex);
        } catch (NoSuchMethodException ex) {
            LOG.log(Level.FATAL, "Can't instantiate page " + clazz + " constructor not found", ex);
        } catch (SecurityException ex) {
            LOG.log(Level.FATAL, null, ex);
        }

        if (p == null) {
            return;
        }
        m_currentPanel.replaceWith(p);
        m_currentPanel = p;
    	updateContextMenu();
    }
}
